﻿Imports System.Drawing.Drawing2D
Imports System.Xml

Public Class Menu
	Public Top As New MenuItem(Me)
	Public ItemHeight As Integer
	Public Right As Integer
	Public Graphics As Graphics
	Public Items As New List(Of MenuItem)
	Friend Code As String
	Public Window As Window
	Public Surface As UserControl

	Dim _Expanded(9) As MenuItem
	Property Expanded(i As Integer) As MenuItem
		Get
			Return _Expanded(i)
		End Get
		Set(value As MenuItem)
			_Expanded(i) = value
			RearrangeLayout()
		End Set
	End Property

	Sub New(Window As Window)
		Me.Window = Window
		Open()
	End Sub

	Sub SetLayout()
		Me.Right = Width
		Top.SubmenuRectangle = New Rectangle(0, -1, Surface.Width, ItemHeight + 6)
		Dim x = 3
		For Each Item In Top.Items
			Item.Location = New Point(x, 2)
			Item.Size = Item.MinSize
			x += Item.Size.Width + 4
		Next
		RearrangeLayout()
	End Sub

	Sub Draw(ByVal G As Graphics, cliprectangle As Rectangle)
		Me.Graphics = G
		Dim R As Rectangle = Top.SubmenuRectangle
		If R.IntersectsWith(cliprectangle) Then
			G.SmoothingMode = SmoothingMode.None
			G.PixelOffsetMode = PixelOffsetMode.None
			G.FillRectangle(New SolidBrush(Color.FromArgb(255 * OpeningOpacity, Color.Black)), R)
		End If
		If Not Expanded(1) Is Nothing Then
			R = DropDown
			R.Inflate(6, 8)
			R.Height -= 1
			R.Width -= 1
			If R.IntersectsWith(cliprectangle) Then
				Themes.Current.Blur(G, Surface, R)
				G.SmoothingMode = SmoothingMode.AntiAlias
				G.PixelOffsetMode = PixelOffsetMode.None
				DrawRoundRect(G, R, New Pen(Color.FromArgb(128, Color.Black)), 8)
				R.Inflate(-2, -2)
				DrawRoundRect(G, R, New Pen(Color.FromArgb(64, Color.Black), 3), 6)
				R.Inflate(-1, -1)
				DrawRoundRect(G, R, New Pen(Color.FromArgb(32, Color.White)), 6)
				R.Inflate(-1, -1)
				FillRoundRect(G, R, Color.White.Opacity(144).Brush, 6)
				DrawRoundRect(G, R, New Pen(Color.FromArgb(128, Color.Black)), 6)
				If Not Expanded(2) Is Nothing Then
					R = DropDown
					R.Offset(Expanded(2).Size.Width + 6, 0)
					R.Inflate(2, 3)
					Dim R1 = Expanded(2).Rectangle
					Dim Path As New GraphicsPath
					Path.AddLines(New Point() {New Point(R.Left, R.Top), New Point(R.Left, R1.Top + R1.Height / 2 - 4), New Point(R.Left - 4, R1.Top + R1.Height / 2), New Point(R.Left, R1.Top + R1.Height / 2 + 4), New Point(R.Left, R.Bottom)})
					G.SmoothingMode = SmoothingMode.None
					G.DrawPath(Color.Black.Opacity(32).Pen, Path)
					Dim m As New Matrix
					m.Translate(1, 0)
					Path.Transform(m)
					G.DrawPath(Color.White.Opacity(32).Pen, Path)
				End If
			End If
		End If
		DrawSubmenu(Top, cliprectangle)
	End Sub

	Sub DrawSubmenu(Menu As MenuItem, cliprectangle As Rectangle)
		For Each Item In Menu.Items
			If Item.Rectangle.IntersectsWith(cliprectangle) Then Item.Draw()
			If Item.IsExpanded Then DrawSubmenu(Item, cliprectangle)
		Next
	End Sub

	Dim m_Focused As MenuItem
	Property Focused() As MenuItem
		Get
			Return m_Focused
		End Get
		Set(ByVal Value As MenuItem)
			Dim prev = Focused
			m_Focused = Value
			If Not prev Is Nothing Then prev.Invalidate()
			If Not Focused Is Nothing Then Focused.Invalidate()
		End Set
	End Property

	Dim m_Selected As MenuItem
	Property Selected() As MenuItem
		Get
			Return m_Selected
		End Get
		Set(ByVal Value As MenuItem)
			If Not Selected Is Nothing Then Selected.Invalidate() : Surface.Cursor = Cursors.Default
			m_Selected = Value
			If Not Selected Is Nothing Then Selected.Invalidate() : Surface.Cursor = Cursors.Hand
		End Set
	End Property

	Function Find(ByVal Key As String) As MenuItem
		Return Top.Find(Key)
	End Function

	Sub RearrangeLayout()
		If Expanded(1) Is Nothing Then
			DropDown = Rectangle.Empty
			Return
		End If
		Dim mx1 = 180, my1 = 0
		For Each Item In Expanded(1).Items
			If Item.MinSize.Width > mx1 Then mx1 = Item.MinSize.Width
		Next
		Dim w = mx1
		Dim y = 0
		For Each Item In Expanded(1).Items
			Item.Size = New Size(mx1, Item.MinSize.Height)
			Item.Location = New Point(0, y)
			y += Item.Size.Height + 1
			If y > my1 Then my1 = y
		Next
		Dim mx2 = 0
		If Not Expanded(2) Is Nothing Then
			mx2 = 180
			mx2 = FindMin(mx2, Expanded(2))
			SetMin(mx1 + 6, mx2, 0, my1, Expanded(2))
			w += mx2 + 6
		End If
		'my1 += 24
		DropDown = New Rectangle(Expanded(1).Location.X + 5, Expanded(1).Location.Y + Expanded(1).MinSize.Height + 13, w, my1)
		Surface.Invalidate()
	End Sub

	Function FindMin(mx2 As Integer, Menu As MenuItem) As Integer
		For Each Item In Menu.Items
			If Item.MinSize.Width > mx2 Then mx2 = Item.MinSize.Width
			If Item.IsExpanded Then mx2 = FindMin(mx2, Item)
		Next
		Return mx2
	End Function

	Dim _OpeningOpacity As Double = 0
	Property OpeningOpacity As Double
		Get
			Return _OpeningOpacity
		End Get
		Set(value As Double)
			_OpeningOpacity = value
		End Set
	End Property

	Sub SetMin(mx1 As Integer, mx2 As Integer, ByRef y As Integer, ByRef my1 As Integer, Menu As MenuItem)
		For Each Item In Menu.Items
			If Item.Text.StartsWith("""") AndAlso Not Menu.Items.IndexOf(Item) = 0 Then y += 5
			Item.Size = New Size(mx2, Item.MinSize.Height)
			Item.Location = New Point(mx1, y)
			y += Item.Size.Height + 1
			If y > my1 Then my1 = y
			If Item.IsExpanded Then SetMin(mx1, mx2, y, my1, Item)
		Next
	End Sub

	Private ReadOnly Property Width() As Integer
		Get
			Return Surface.Width
		End Get
	End Property

	Function TextWidth(ByVal Text As String) As Integer
		Return MeasureText(Text, Window.Font).Width
	End Function

	Function ProcessKey(ByVal KeyData As System.Windows.Forms.Keys) As Boolean
		If Focused.IsTopMenu Then
			Select Case KeyData
				Case Keys.Up : KeyData = Keys.Left
				Case Keys.Down : KeyData = Keys.Right
				Case Keys.Left : KeyData = Keys.Up
				Case Keys.Right : KeyData = Keys.Down
			End Select
		End If
		Select Case KeyData
			Case Keys.Down : Focused.GoDown() : Return True
			Case Keys.Up : Focused.GoUp() : Return True
			Case Keys.Right : Focused.GoRight() : Return True
			Case Keys.Left, Keys.Back : Focused.GoLeft() : Return True
			Case Keys.Escape : Focused.Close() : Return True
			Case Keys.Enter : Focused.Activate() : Return True
		End Select
	End Function

	Public Sub Focus(ByVal Key As String)
		Dim Item As MenuItem = Find(Key)
		If Item Is Nothing Then Return
		Focused = Item
		Item.EnsureVisible()
	End Sub

	Sub MouseMove(ByVal Point As Point)
		If Not Selected Is Nothing Then
			If Selected.Rectangle.Contains(Point) Then Exit Sub
			Selected.Deselect()
		End If
		Dim Item = CheckMouse(Top, Point)
		If Item Is Nothing Then Return
		Item.Select()
	End Sub

	Function CheckMouse(Menu As MenuItem, Point As Point) As MenuItem
		For Each Item In Menu.Items
			If Item.Selectable(Point) Then Return Item
			If Item.IsExpanded Then
				Dim i1 = CheckMouse(Item, Point)
				If Not i1 Is Nothing Then Return i1
			End If
		Next
		Return Nothing
	End Function

	Dim _DropDown As Rectangle = Rectangle.Empty
	Property DropDown As Rectangle
		Get
			Return _DropDown
		End Get
		Set(value As Rectangle)
			Dim R = _DropDown
			R.Inflate(8, 8)
			Surface.Invalidate(R)
			If value.Right > Right Then
				value.Offset(Right - value.Right, 0)
			End If
			_DropDown = value
			If value.IsEmpty Then Return
			R = _DropDown
			R.Inflate(8, 8)
			Surface.Invalidate(R)
		End Set
	End Property

	Function Save() As Boolean
		Dim Doc As New XmlDocument
		Dim Data = Doc.CreateNode(Xml.XmlNodeType.Element, "data", Doc.NamespaceURI)
		Doc.AppendChild(Data)
		Doc.PreserveWhitespace = True
		Top.Save(Data)
		Try
			My.Computer.FileSystem.WriteAllText("..\..\Resources\MenuXML.txt", Doc.InnerXml, False, System.Text.Encoding.Default)
			Return True
		Catch ex As Exception
			Warning("Menü kaydedilemedi. MenuXML.txt dosyası checked-in olmalıdır.")
		End Try
	End Function

	Sub Open()
		Dim Doc As New XmlDocument
		Doc.InnerXml = My.Resources.MenuXML
		Dim Data = Doc.FirstChild
		Top.Text = "Ana sayfa"
		Top.Open(Data.FirstChild)
		Measure()
	End Sub

	Sub Measure()
		Graphics = Window.CreateGraphics
		ItemHeight = Graphics.MeasureString("x", Themes.Current.Font).Height + 8
		Top.Measure()
	End Sub

End Class
